#include "partition_table.h"
#include "main.h"
#include "stdio.h"

int32_t get_sector_from_addr(uint32_t Address)
{
    int32_t sector = -1;

    if ((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
    {
        sector = FLASH_SECTOR_0;
    }
    else if ((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
    {
        sector = FLASH_SECTOR_1;
    }
    else if ((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
    {
        sector = FLASH_SECTOR_2;
    }
    else if ((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
    {
        sector = FLASH_SECTOR_3;
    }
    else if ((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
    {
        sector = FLASH_SECTOR_4;
    }
    else if ((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
    {
        sector = FLASH_SECTOR_5;
    }
    else if ((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
    {
        sector = FLASH_SECTOR_6;
    }
    else if ((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
    {
        sector = FLASH_SECTOR_7;
    }
    else if ((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
    {
        sector = FLASH_SECTOR_8;
    }
    else if ((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
    {
        sector = FLASH_SECTOR_9;
    }
    else if ((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
    {
        sector = FLASH_SECTOR_10;
    }
    else if ((Address < ADDR_FLASH_SECTOR_12) && (Address >= ADDR_FLASH_SECTOR_11))
    {
        sector = FLASH_SECTOR_11;
    }
    else if ((Address < ADDR_FLASH_SECTOR_13) && (Address >= ADDR_FLASH_SECTOR_12))
    {
        sector = FLASH_SECTOR_12;
    }
    else if ((Address < ADDR_FLASH_SECTOR_14) && (Address >= ADDR_FLASH_SECTOR_13))
    {
        sector = FLASH_SECTOR_13;
    }
    else if ((Address < ADDR_FLASH_SECTOR_15) && (Address >= ADDR_FLASH_SECTOR_14))
    {
        sector = FLASH_SECTOR_14;
    }
    else if ((Address < ADDR_FLASH_SECTOR_16) && (Address >= ADDR_FLASH_SECTOR_15))
    {
        sector = FLASH_SECTOR_15;
    }
    else if ((Address < ADDR_FLASH_SECTOR_17) && (Address >= ADDR_FLASH_SECTOR_16))
    {
        sector = FLASH_SECTOR_16;
    }
    else if ((Address < ADDR_FLASH_SECTOR_18) && (Address >= ADDR_FLASH_SECTOR_17))
    {
        sector = FLASH_SECTOR_17;
    }
    else if ((Address < ADDR_FLASH_SECTOR_19) && (Address >= ADDR_FLASH_SECTOR_18))
    {
        sector = FLASH_SECTOR_18;
    }
    else if ((Address < ADDR_FLASH_SECTOR_20) && (Address >= ADDR_FLASH_SECTOR_19))
    {
        sector = FLASH_SECTOR_19;
    }
    else if ((Address < ADDR_FLASH_SECTOR_21) && (Address >= ADDR_FLASH_SECTOR_20))
    {
        sector = FLASH_SECTOR_20;
    }
    else if ((Address < ADDR_FLASH_SECTOR_22) && (Address >= ADDR_FLASH_SECTOR_21))
    {
        sector = FLASH_SECTOR_21;
    }
    else if ((Address < ADDR_FLASH_SECTOR_23) && (Address >= ADDR_FLASH_SECTOR_22))
    {
        sector = FLASH_SECTOR_22;
    }
    else /*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_23))*/
    {
        sector = FLASH_SECTOR_23;
    }
    return sector;
}

int8_t read_settings_boot_state(void)
{
    return *(__IO uint8_t *)(SETTING_SECTOR_ADDR);
}

int8_t write_settings_boot_state(uint8_t state)
{
    uint32_t sector_index;
    HAL_StatusTypeDef res;
    uint32_t read_buf;
    read_buf = *(__IO uint32_t *)(SETTING_SECTOR_ADDR); // 先把前四个字节数据读出来

    res = HAL_FLASH_Unlock();
    if (res != HAL_OK)
    {
        printf("FLASH_UNLOCK ERROR\r\n");
        return -1;
    }
    sector_index = get_sector_from_addr(SETTING_SECTOR_ADDR);
    printf("[Bootloader]Erase ADDR 0x%08lx; Sector No.%ld...\r\n", SETTING_SECTOR_ADDR, sector_index);
    FLASH_Erase_Sector(sector_index, FLASH_VOLTAGE_RANGE_3);
    printf("[Bootloader]Flash ADDR 0x%08lx ...\r\n", SETTING_SECTOR_ADDR);

    // 把想要写入的信息写入readbuf中去，最后把32位信息一起写进去
    read_buf &= 0xffffff00; // 先把第一个字节数据清0,FLASH是高字节存储在高位，低字节存储在低位，所以应该把低字节设置为0
    read_buf |= state;

    res = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, SETTING_SECTOR_ADDR, read_buf);
    if (res != HAL_OK)
    {
        printf("[Bootloader]FLASH_WRITE ERROR\r\n");
        return -1;
    }
    res = HAL_FLASH_Lock();
    if (res != HAL_OK)
    {
        printf("[Bootloader]FLASH_LOCK ERROR\r\n");
        return -1;
    }
    return 0;
}

int8_t read_settings_boot_partition(void)
{
    return *(__IO uint8_t *)(SETTING_SECTOR_ADDR + SETTING_BOOT_PARTITION_OFFSET);
}

int8_t write_settings_boot_partition(int8_t state)
{
    int sector_index;
    HAL_StatusTypeDef res;
    uint32_t read_buf;
    read_buf = *(__IO uint32_t *)(SETTING_SECTOR_ADDR); // 先把前四个字节数据读出来

    res = HAL_FLASH_Unlock();
    if (res != HAL_OK)
    {
        printf("FLASH_UNLOCK ERROR\r\n");
        return -1;
    }
    sector_index = get_sector_from_addr(SETTING_SECTOR_ADDR);
    printf("[Bootloader]Erase ADDR 0x%08lx; Sector No.%d...\r\n", SETTING_SECTOR_ADDR, sector_index);
    FLASH_Erase_Sector(sector_index, FLASH_VOLTAGE_RANGE_3);
    printf("[Bootloader]Flash ADDR 0x%08lx ...\r\n", SETTING_SECTOR_ADDR);

    // 把想要写入的信息写入readbuf中去，最后把32位信息一起写进去
    read_buf &= 0xffff00ff;   // 先把第二个字节数据清0,FLASH是高字节存储在高位，低字节存储在低位，所以应该把低字节设置为0
    read_buf |= (state << 8); // 放在第二个字节的位置

    res = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, SETTING_SECTOR_ADDR, read_buf);
    if (res != HAL_OK)
    {
        printf("[Bootloader]FLASH_WRITE ERROR\r\n");
        return -1;
    }
    res = HAL_FLASH_Lock();
    if (res != HAL_OK)
    {
        printf("[Bootloader]FLASH_LOCK ERROR\r\n");
        return -1;
    }
    return 0;
}

// FLash Function
/**
 * @brief  This function does an erase of all user flash area
 * @param  StartSector: start of user flash area
 * @retval 0: user flash area successfully erased
 *         1: error occurred
 */
uint32_t flash_erase(uint32_t StartAdd)
{
    uint32_t UserStartSector;
    uint32_t SectorError;
    FLASH_EraseInitTypeDef pEraseInit;

    HAL_FLASH_Unlock();

    /* Get the sector where start the user flash area */
    UserStartSector = get_sector_from_addr(StartAdd);

    pEraseInit.TypeErase = TYPEERASE_SECTORS;
    pEraseInit.Sector = UserStartSector;
    pEraseInit.NbSectors = 5;
    pEraseInit.VoltageRange = VOLTAGE_RANGE_3;

    if (HAL_FLASHEx_Erase(&pEraseInit, &SectorError) != HAL_OK)
    {
        /* Error occurred while page erase */
        return (1);
    }

    HAL_FLASH_Lock();

    return (0);
}

/**
 * @brief  This function writes a data buffer in flash (data are 32-bit aligned).
 * @note   After writing data buffer, the flash content is checked.
 * @param  StartAddress: start address for writing data buffer
 * @param  EndAddress: end address for writing data buffer
 * @param  Data: pointer on data buffer
 * @param  DataLength: length of data buffer (unit is 32-bit word)
 * @retval 0: Data successfully written to Flash memory
 *         -2: Error occurred while writing data in Flash memory
 *         -1: Written Data in flash memory is different from expected one
 */
int8_t flash_write_continue(uint32_t StartAddress, uint32_t EndAddress,
                            uint32_t *Data, uint32_t DataLength)
{
    int32_t i = 0;

    HAL_FLASH_Unlock();
    for (i = 0; (i < DataLength) && (StartAddress <= (EndAddress - 4)); i++)
    {
        /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
           be done by word */
        if (HAL_FLASH_Program(TYPEPROGRAM_WORD, StartAddress, *(uint32_t *)(Data + i)) == HAL_OK)
        {
            /* Check the written value */
            if (*(uint32_t *)StartAddress != *(uint32_t *)(Data + i))
            {
                /* Flash content doesn't match SRAM content */
                return (-1);
            }
            /* Increment FLASH destination address */
            StartAddress += 4;
        }
        else
        {
            /* Error occurred while writing data in Flash memory */
            return (-2);
        }
    }
    HAL_FLASH_Lock();
    return (0);
}
